Skip to content

Native open/save file dialogs with platform hints, options and preview - #6052

Merged
shai-almog merged 36 commits into
masterfrom
native-file-dialogs
Oct 22, 2026
Merged

shai-almog merged 36 commits into
masterfrom
native-file-dialogs

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Adds native save dialogs, plus open dialogs you can customize, in the new package com.codename1.io.filechooser.

API

  • Display.showOpenDialog(OpenFileRequest, cb) and Display.showSaveDialog(SaveFileRequest, cb). The callback runs on the EDT, including when the user cancels.
  • Requests take a title, a message, an accept label, an initial folder, named filters (FileTypeFilter: extensions, MIME types, UTTypes), a suggested name, multi-select or folder picking, and overwrite confirmation.
  • Portable FileDialogOptions (checkbox, choice, text) show up inside the native dialog where the platform allows it, and their values come back in FileDialogResult.
  • FileDialogHints are platform hints (macOS tag field, Windows client GUID, Android initial URI, ...). A platform ignores the hints it doesn't know.
  • FilePreviewProvider gives a live preview while opening. An accessory Component can be added too.
  • A save gets its content from SaveContent (written after the user picks a location and format) or from an existing file.
  • Display.isFileDialogFeatureSupported(...) is a runtime capability query.
  • On platforms without a native dialog, a Codename One fallback is used. openFileChooser is unchanged.

Ports

Platform Open Save Extras
JavaSE / simulator AWT FileDialog, or Swing JFileChooser same filters, options, preview
Android Storage Access Framework (SAF) document picker ACTION_CREATE_DOCUMENT none
iOS UIDocumentPicker temp file, then export none
macOS NSOpenPanel NSSavePanel filters, options, hints
Windows IFileOpenDialog IFileSaveDialog filters, options via IFileDialogCustomize, hints
Linux GtkFileChooser GtkFileChooser filters, options
JavaScript file picker download none

Known limitations

  • A native dialog never embeds an accessory component; only the fallback form shows one. Preview works only on JavaSE.
  • Android and iOS don't report the selected filter or option values (the defaults are returned).
  • macOS filters by extension through allowedFileTypes, which is deprecated on macOS 12 and later, and always confirms before overwriting.

Verification

  • New unit tests: FileDialogRequestTest and FileDialogSupportTest.
  • SpotBugs, PMD and Checkstyle are clean on core. SpotBugs is clean on Android and iOS.
  • The native signature check passes on iOS. The C++ linkage check passes on Windows.
  • Linux and Windows natives were never compiled locally; this relies on CI. No dialog has been run on a device yet.

🤖 Generated with Claude Code

shai-almog and others added 12 commits October 19, 2026 14:18
… previews

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…review

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…download

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d options

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Open uses initForOpeningContentTypes (filter UTTypes, extensions, folder),
multi-select, directoryURL and shouldShowFileExtensions; picked items are
copied to tmp. Save stages content in the caches dir off the EDT and exports
it with initForExportingURLs asCopy. Results return through a per-request id
and are delivered on the EDT.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…filters, options and hints

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Filters become an accessory popup that switches the allowed types, options
render as checkbox/popup/text controls in the same accessory stack, and the
MAC_* hints map to the panel properties. Answers use NativeFileDialogCodec;
saves are written through completeSaveDialog. No accessory Component or
preview on the Mac yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog

shai-almog commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 12 screenshots: 12 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ✅ ByteCodeTranslator: 0 findings (no issues)
    • ✅ android: 0 findings (no issues)
    • ✅ android-compat: 0 findings (no issues)
    • ✅ android-res-compiler: 0 findings (no issues)
    • ✅ backend: 0 findings (no issues)
    • ✅ backend-test: 0 findings (no issues)
    • ✅ build-engine: 0 findings (no issues)
    • ✅ build-hint-catalog: 0 findings (no issues)
    • ✅ build-hint-tools: 0 findings (no issues)
    • ✅ codenameone-gradle-plugin: 0 findings (no issues)
    • ✅ codenameone-maven-plugin: 0 findings (no issues)
    • ✅ core-unittests: 0 findings (no issues)
    • ✅ ios: 0 findings (no issues)
    • ✅ javac: 0 findings (no issues)
    • ✅ project-model: 0 findings (no issues)
  • ✅ PMD: 0 findings (no issues) [Report archive]
  • ✅ Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@github-actions

Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review 🔄 Running since 2026-10-21T11:37:03.210647Z 3967c08 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@shai-almog

shai-almog commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 214 screenshots: 214 matched.
✅ JavaScript-port screenshot tests passed.

@shai-almog

shai-almog commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 178 screenshots: 178 matched.

Native Android coverage

  • 📊 Line coverage: 17.40% (30683/176345 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 15.70% (144927/923101), branch 10.67% (10018/93896), complexity 8.23% (7454/90604), method 12.02% (5159/42930), class 20.76% (1060/5105)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6367 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/736 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/625 lines covered)
      • com.codename1.androidcompat.rt.com.codename1.androidcompat.rt.TextXmlPullParser – 0.00% (0/623 lines covered)
      • com.codename1.androidcompat.androidx.constraintlayout.core.widgets.com.codename1.androidcompat.androidx.constraintlayout.core.widgets.Flow – 0.00% (0/576 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 17.40% (30683/176345 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 15.70% (144927/923101), branch 10.67% (10018/93896), complexity 8.23% (7454/90604), method 12.02% (5159/42930), class 20.76% (1060/5105)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6367 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/736 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/625 lines covered)
      • com.codename1.androidcompat.rt.com.codename1.androidcompat.rt.TextXmlPullParser – 0.00% (0/623 lines covered)
      • com.codename1.androidcompat.androidx.constraintlayout.core.widgets.com.codename1.androidcompat.androidx.constraintlayout.core.widgets.Flow – 0.00% (0/576 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend scalar fallback (no native SIMD)
SIMD int-add (64K x300) java 93ms / native 19ms = 4.8x speedup
SIMD float-mul (64K x300) java 64ms / native 53ms = 1.2x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 52.000 ms
Base64 CN1 decode 51.000 ms
Base64 native encode 315.000 ms
Base64 encode ratio (CN1/native) 0.165x (83.5% faster)
Base64 native decode 183.000 ms
Base64 decode ratio (CN1/native) 0.279x (72.1% faster)
Image encode benchmark status skipped (SIMD unsupported)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 71c2a5a6ee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/NativeFileDialogCodec.java
Comment thread Ports/Android/src/com/codename1/impl/android/AndroidFileDialogs.java Outdated
Comment thread CodenameOne/src/com/codename1/impl/FileDialogSupport.java Outdated
Comment thread Ports/Android/src/com/codename1/impl/android/AndroidFileDialogs.java Outdated
Comment thread Ports/iOSPort/nativeSources/IOSNative.m
Comment thread Ports/LinuxPort/src/com/codename1/impl/linux/LinuxImplementation.java Outdated
Comment thread Ports/iOSPort/nativeSources/IOSNative.m Outdated
@shai-almog

shai-almog commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 193 screenshots: 193 matched.
Native Windows port, REAL shipping pipeline: the hellocodenameone screenshot suite rendered by a binary CROSS-COMPILED on Linux (clang-cl + xwin, WebView2 linked) and RUN on a Windows x64 runner. Compared against the in-repo baseline in scripts/windows/screenshots.

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 31ms / native 2ms = 15.5x speedup
SIMD float-mul (64K x300) java 28ms / native 2ms = 14.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 34.000 ms
Base64 CN1 decode 44.000 ms
Base64 SIMD encode 50.000 ms
Base64 encode ratio (SIMD/CN1) 1.471x (47.1% slower)
Base64 SIMD decode 51.000 ms
Base64 decode ratio (SIMD/CN1) 1.159x (15.9% slower)
Image encode benchmark iterations 100
Image createMask (SIMD off) 5.000 ms
Image createMask (SIMD on) 2.000 ms
Image createMask ratio (SIMD on/off) 0.400x (60.0% faster)
Image applyMask (SIMD off) 18.000 ms
Image applyMask (SIMD on) 13.000 ms
Image applyMask ratio (SIMD on/off) 0.722x (27.8% faster)
Image modifyAlpha (SIMD off) 15.000 ms
Image modifyAlpha (SIMD on) 10.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.667x (33.3% faster)
Image modifyAlpha removeColor (SIMD off) 21.000 ms
Image modifyAlpha removeColor (SIMD on) 11.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.524x (47.6% faster)

- Copyright headers on the new tests; classify the fallback save form in
  FrameworkChromeNeverWindowsTest; Vale quote punctuation in the guide.
- Linux: add the filter's extension in the GTK native and confirm the
  overwrite of that name, since GTK only checked the typed basename.
- Core: saving a sourceFile onto itself no longer truncates it.
- Android: refuse to launch while another activity result is outstanding;
  stop reporting INITIAL_DIRECTORY, which only the URI hint honours.
- iOS: convert extension filters to legacy UTIs before iOS 14; copy picked
  documents off the main thread.
- JavaScript: report a dismissed picker as cancelled; a save too large for
  the heap still answers the callback.
- Linux/Windows: deliver results on the EDT.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c6b20e3220

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/FileDialogSupport.java Outdated
Comment thread Ports/JavaSE/src/com/codename1/impl/javase/JavaSEFileDialogs.java
Comment thread Ports/JavaSE/src/com/codename1/impl/javase/JavaSEFileDialogs.java
Comment thread CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java Outdated
Comment thread Ports/Android/src/com/codename1/impl/android/AndroidFileDialogs.java Outdated
Comment thread CodenameOne/src/com/codename1/impl/NativeFileDialogCodec.java
@shai-almog

shai-almog commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 193 screenshots: 193 matched.
Native Windows port (x64 / Intel-AMD): full hellocodenameone screenshot suite rendered offscreen with Direct2D/DirectWrite, plus the real benchmarks (base64 native/CN1/SIMD, image createMask/applyMask/modifyAlpha/PNG/JPEG, SSE2 SIMD kernels). Compared against the in-repo baseline in scripts/windows/screenshots.

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 66ms / native 5ms = 13.2x speedup
SIMD float-mul (64K x300) java 68ms / native 6ms = 11.3x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 69.000 ms
Base64 CN1 decode 85.000 ms
Base64 SIMD encode 98.000 ms
Base64 encode ratio (SIMD/CN1) 1.420x (42.0% slower)
Base64 SIMD decode 90.000 ms
Base64 decode ratio (SIMD/CN1) 1.059x (5.9% slower)
Image encode benchmark iterations 100
Image createMask (SIMD off) 11.000 ms
Image createMask (SIMD on) 6.000 ms
Image createMask ratio (SIMD on/off) 0.545x (45.5% faster)
Image applyMask (SIMD off) 51.000 ms
Image applyMask (SIMD on) 52.000 ms
Image applyMask ratio (SIMD on/off) 1.020x (2.0% slower)
Image modifyAlpha (SIMD off) 85.000 ms
Image modifyAlpha (SIMD on) 31.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.365x (63.5% faster)
Image modifyAlpha removeColor (SIMD off) 58.000 ms
Image modifyAlpha removeColor (SIMD on) 35.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.603x (39.7% faster)

ParparVM vs HotSpot (JDK 25): Windows x64

Runner CPU: Intel64 Family 6 Model 207 Stepping 2, GenuineIntel (baseline windows-x64@intel64-family-6-model-207-genuineintel)

1 performance regression:

  • translator (self) on all 4 CPUs: time 0.74x against a 0.59x baseline (+24.6%, tolerance 20%)

Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in vm/selfhost/perf-baseline/ is a regression and fails; one that far below is an improvement, reported but not failed (a row whose calibration runs were noisier carries a wider tolerance), and for RAM the change must also exceed 0.05x in absolute terms. Both run unpinned on all of the runner's CPUs, with their own default thread counts.

Benchmark Cores Time RAM Status
hello (WinHelloMain) 4 1.22x (base 1.07x, +14.3%) 0.67x (base 0.86x, -22.3%) ok
translator (self) 4 0.74x (base 0.59x, +24.6%) 0.52x (base 0.53x, -1.5%) REGRESSION (time +24.6%)
intArithmetic 4 1.03x (base 1.02x, +0.0%) 0.06x (base 0.06x, +0.4%) ok
longArithmetic 4 0.97x (base 0.97x, -0.3%) 0.05x (base 0.05x, +1.8%) ok
mathTranscendental 4 0.89x (base 0.89x, +0.1%) 0.06x (base 0.06x, -3.4%) ok
arraySequential 4 1.67x (base 1.98x, -15.5%) 0.38x (base 0.38x, +0.1%) ok
arrayRandom 4 1.01x (base 1.01x, -0.1%) 0.23x (base 0.23x, +0.4%) ok
objectAllocation 4 1.25x (base 1.22x, +2.9%) 0.33x (base 0.37x, -10.8%) ok
valueEscape 4 0.13x (base 0.13x, +3.0%) 0.05x (base 0.04x, +2.4%) ok
hashMapChurn 4 1.16x (base 1.14x, +1.6%) 0.10x (base 0.10x, -0.3%) ok
stringBuilding 4 1.52x (base 1.42x, +7.1%) 0.26x (base 0.22x, +16.8%) ok
recursion 4 1.20x (base 1.20x, -0.3%) 0.06x (base 0.06x, +1.6%) ok
quicksort 4 1.06x (base 1.07x, -0.3%) 0.12x (base 0.12x, +0.8%) ok

A change that moves performance ON PURPOSE records the new baseline in vm/selfhost/perf-baseline/pr/6052.json, with the reason, from this job's perf-results.json. The rebaseline is then part of this pull request's diff:

python3 vm/selfhost/calibrate-perf-baseline.py --pr 6052 --reason "<why these benchmarks moved>" perf-results.json

Result: performance regression

- Core: a content writer still runs when the destination is the source
  file; the default implementation no longer advertises INITIAL_DIRECTORY.
- JavaSE: filtered saves (and filtered opens on Windows, where AWT's
  FilenameFilter does nothing) use the Swing chooser, which confirms the
  overwrite of the name with the extension added.
- Android: picks are checked against extension filters the MIME query could
  not express; a picked folder is copied to the cache so the result is a
  path FileSystemStorage can use.
- macOS: filters given as UTIs reach allowedFileTypes.
- iOS: close the staged export stream in a finally (SpotBugs DLS).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7879337058

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Ports/WindowsPort/nativeSources/cn1_windows_filedialog.cpp Outdated
Comment thread CodenameOne/src/com/codename1/impl/FileDialogSupport.java
Comment thread Ports/JavaSE/src/com/codename1/impl/javase/JavaSEFileDialogs.java
Comment thread Ports/JavaSE/src/com/codename1/impl/javase/JavaSEFileDialogs.java Outdated
Comment thread Ports/JavaSE/src/com/codename1/impl/javase/JavaSEFileDialogs.java
Comment thread Ports/iOSPort/src/com/codename1/impl/ios/IOSImplementation.java
Comment thread Ports/iOSPort/nativeSources/IOSNative.m Outdated
- Windows: an IFileDialogEvents sink keeps the save dialog's default
  extension on the selected filter, so switching type no longer yields
  report.pdf.png.
- Core: the fallback save form runs on the EDT when called from another
  thread, and the open fallback delivers on the EDT.
- JavaSE: drop a preview render that finishes after the selection moved;
  parse file:/ and drive-letter URLs for the starting folder; saves that
  must not confirm an overwrite use the Swing chooser.
- iOS: watchOS and tvOS use the Codename One fallback; a picker requested
  while another controller is presented answers cancelled instead of
  hanging.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31852b9dda

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Ports/LinuxPort/nativeSources/cn1_linux_services.c Outdated
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cfb4b397b9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Ports/Android/src/com/codename1/impl/android/AndroidFileDialogs.java Outdated
Comment thread Ports/Android/src/com/codename1/impl/android/AndroidFileDialogs.java Outdated
Comment thread Ports/iOSPort/src/com/codename1/impl/ios/IOSImplementation.java
Comment thread CodenameOne/src/com/codename1/impl/FileDialogSupport.java
Comment thread Ports/iOSPort/nativeSources/IOSNative.m Outdated
shai-almog and others added 2 commits October 21, 2026 11:45
…ard and coordinated copy, unchecked writer failures

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 90ee77db25

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Ports/iOSPort/src/com/codename1/impl/ios/IOSImplementation.java
Comment thread Ports/Android/src/com/codename1/impl/android/AndroidFileDialogs.java Outdated
Comment thread CodenameOne/src/com/codename1/io/filechooser/FileDialogRequest.java
… failure, wildcard fallback accept

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f37784b340

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CodenameOne/src/com/codename1/impl/NativeFileDialogCodec.java
…e accept union

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog

Copy link
Copy Markdown
Collaborator Author

@codex review

…parators

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog

shai-almog commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 179 screenshots: 179 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 383 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 54ms / native 3ms = 18.0x speedup
SIMD float-mul (64K x300) java 55ms / native 3ms = 18.3x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 50.000 ms
Base64 CN1 decode 56.000 ms
Image encode benchmark iterations 100
Image createMask (SIMD off) 9.000 ms
Image createMask (SIMD on) 4.000 ms
Image createMask ratio (SIMD on/off) 0.444x (55.6% faster)
Image applyMask (SIMD off) 62.000 ms
Image applyMask (SIMD on) 64.000 ms
Image applyMask ratio (SIMD on/off) 1.032x (3.2% slower)
Image modifyAlpha (SIMD off) 52.000 ms
Image modifyAlpha (SIMD on) 60.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.154x (15.4% slower)
Image modifyAlpha removeColor (SIMD off) 70.000 ms
Image modifyAlpha removeColor (SIMD on) 75.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.071x (7.1% slower)

ParparVM vs HotSpot (JDK 25): macOS arm64

Runner CPU: Apple M1 (Virtual) (baseline macos-arm64)

Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in vm/selfhost/perf-baseline/ is a regression and fails; one that far below is an improvement, reported but not failed (a row whose calibration runs were noisier carries a wider tolerance), and for RAM the change must also exceed 0.05x in absolute terms. Both run unpinned on all of the runner's CPUs, with their own default thread counts.

Benchmark Cores Time RAM Status
hello (HelloCodenameOne) 3 0.71x (base 0.96x, -26.0%) 0.93x (base 0.93x, +0.7%) ok
translator (self) 3 0.63x (base 0.62x, +0.7%) 0.64x (base 0.58x, +11.9%) ok
intArithmetic 3 1.04x (base 1.03x, +1.0%) 0.12x (base 0.12x, +1.5%) ok
longArithmetic 3 1.05x (base 1.03x, +2.2%) 0.11x (base 0.07x, +60.7%) ok
mathTranscendental 3 0.99x (base 1.01x, -1.7%) 0.12x (base 0.12x, +0.5%) ok
arraySequential 3 0.45x (base 0.42x, +7.9%) 0.53x (base 0.53x, +0.5%) ok
arrayRandom 3 0.97x (base 0.99x, -1.5%) 0.32x (base 0.32x, +0.1%) ok
objectAllocation 3 1.00x (base 1.11x, -9.9%) 0.66x (base 0.72x, -9.1%) ok
valueEscape 3 0.51x (base 0.51x, +0.4%) 0.09x (base 0.09x, +5.0%) ok
hashMapChurn 3 1.07x (base 1.18x, -8.9%) 0.07x (base 0.07x, +0.3%) ok
stringBuilding 3 0.93x (base 0.84x, +10.3%) 0.54x (base 0.46x, +16.6%) ok
recursion 3 1.24x (base 1.24x, +0.3%) 0.12x (base 0.12x, -0.0%) ok
quicksort 3 0.99x (base 1.01x, -2.4%) 0.11x (base 0.11x, +0.3%) ok

Result: no regression

@shai-almog

shai-almog commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 176 screenshots: 176 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 1737 seconds

Build and Run Timing

Metric Duration
Simulator Boot 60000 ms
Simulator Boot (Run) 1000 ms
App Install 23000 ms
App Launch 3000 ms
Test Execution 604000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 70ms / native 4ms = 17.5x speedup
SIMD float-mul (64K x300) java 96ms / native 3ms = 32.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 67.000 ms
Base64 CN1 decode 79.000 ms
Base64 native encode 718.000 ms
Base64 encode ratio (CN1/native) 0.093x (90.7% faster)
Base64 native decode 682.000 ms
Base64 decode ratio (CN1/native) 0.116x (88.4% faster)
Base64 SIMD encode 77.000 ms
Base64 encode ratio (SIMD/CN1) 1.149x (14.9% slower)
Base64 SIMD decode 73.000 ms
Base64 decode ratio (SIMD/CN1) 0.924x (7.6% faster)
Base64 encode ratio (SIMD/native) 0.107x (89.3% faster)
Base64 decode ratio (SIMD/native) 0.107x (89.3% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 7.000 ms
Image createMask (SIMD on) 3.000 ms
Image createMask ratio (SIMD on/off) 0.429x (57.1% faster)
Image applyMask (SIMD off) 95.000 ms
Image applyMask (SIMD on) 44.000 ms
Image applyMask ratio (SIMD on/off) 0.463x (53.7% faster)
Image modifyAlpha (SIMD off) 116.000 ms
Image modifyAlpha (SIMD on) 70.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.603x (39.7% faster)
Image modifyAlpha removeColor (SIMD off) 82.000 ms
Image modifyAlpha removeColor (SIMD on) 533.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 6.500x (550.0% slower)

@github-actions

Copy link
Copy Markdown
Contributor

Flutter vs Codename One

Same application, built both ways: Flutter's AOT compile of the gallery, and the identical Dart source transpiled to Java on Codename One. Lower is better for every metric, so a ratio above 1.00x means Codename One is ahead by that factor.

android

9 interleaved rounds; host load 0.51, 1.68, 1.46

Metric Codename One Flutter Ratio Winner
Installed size 78.2 MB 95.8 MB 1.23x Codename One
Executable code 4.6 MB 20.6 MB 4.43x Codename One
Download size (zipped) 78.2 MB 95.8 MB 1.23x Codename One
Cold start to first frame on screen 415 ms 1669 ms 3.49x Codename One
Memory at rest 44.3 MB 78.1 MB 1.76x Codename One

Start-up and memory at rest are judged round by round: the ratio is the median of the per-round ratios, each from two launches made back to back, and the times and sizes shown are each side's median, so the ratio need not equal their quotient. Codename One was ahead in 9 of 9 rounds on cold start to first frame on screen; 9 of 9 rounds on memory at rest.

Compute -- the VM workloads (vm/benchmarks), run inside each app; time is the best of the app's own repetitions, higher ratio means Codename One is faster.

Workload Codename One Flutter Ratio
intArithmetic 89 ms 187 ms 2.10x
longArithmetic 65 ms 58 ms 0.89x
mathTranscendental 228 ms 348 ms 1.53x
arraySequential 27 ms 36 ms 1.33x
arrayRandom 345 ms 404 ms 1.17x
objectAllocation 70 ms 48 ms 0.69x
valueEscape 7 ms 7 ms 1.00x
hashMapChurn 145 ms 314 ms 2.17x
stringBuilding 97 ms 127 ms 1.31x
recursion 87 ms 272 ms 3.13x
quicksortBench 128 ms 152 ms 1.19x
Geometric mean 1.37x

Gate: within tolerance against scripts/flutter-bench/baseline.

Android sizes are for the arm64-v8a slice a phone is delivered, on both sides; Flutter's release apk carries three ABIs and would otherwise count its engine about three times.
Android start-up and memory come from an x86_64 emulator with a software GPU. They compare the two runtimes on one machine; they are not phone timings, and a renderer that leans on the GPU is penalised more there.
This platform's adapter has not been exercised end to end before; treat the first published run as the thing under review.

ios

9 interleaved rounds; host load 37.1, 31.5, 18.11

Metric Codename One Flutter Ratio Winner
Installed size 107.8 MB 110.5 MB 1.02x Codename One
Executable code 16.8 MB 19.1 MB 1.13x Codename One
Download size (zipped) 79.9 MB 81.9 MB 1.02x Codename One
Cold start to first frame on screen -- -- -- not measured
Memory at rest -- -- -- not measured

Compute -- the VM workloads (vm/benchmarks), run inside each app; time is the best of the app's own repetitions, higher ratio means Codename One is faster.

Not measured: iOS compute is not measured: a device build needs signed hardware, and on the simulator Flutter runs its JIT debug engine rather than AOT code. The macOS row runs the same ParparVM and Dart AOT compilers on the same Apple silicon.

Gate: within tolerance against scripts/flutter-bench/baseline. Smaller than its baseline, which does not fail the gate: Executable code -9.11%; Installed size -1.54%; Download size (zipped) -0.75% -- rebaseline to tighten. To accept the move, download this platform's baseline-<platform>.json artifact and run python3 scripts/flutter-bench/flutter_baseline.py calibrate --pr 6052 --reason "<why these moved>" baseline-ios.json, then commit the overlay it writes.

iOS start-up and memory are not measured here: Flutter cannot AOT-compile for the simulator, so a simulator run would time a JIT debug build against a release build. Sizes come from release device bundles; timings need signed hardware.
This platform's adapter has not been exercised end to end before; treat the first published run as the thing under review.

javascript

9 interleaved rounds; host load 2.04, 1.33, 0.59

Metric Codename One Flutter Ratio Winner
Installed size 103.9 MB 122.5 MB 1.18x Codename One
Executable code 12.8 MB 25.2 MB 1.97x Codename One
Download size (zipped) 76.3 MB 84.1 MB 1.10x Codename One
Cold start to first frame on screen -- -- -- not measured
Memory at rest -- -- -- not measured

Compute -- the VM workloads (vm/benchmarks), run inside each app; time is the best of the app's own repetitions, higher ratio means Codename One is faster.

Workload Codename One Flutter Ratio
intArithmetic 648 ms wrong result Flutter: wrong result
longArithmetic 5126 ms did not run Flutter: did not run
mathTranscendental 562 ms did not run Flutter: did not run
arraySequential 230 ms 82 ms 0.36x
arrayRandom 1008 ms wrong result Flutter: wrong result
objectAllocation 38 ms 27 ms 0.71x
valueEscape 153 ms 7 ms 0.05x
hashMapChurn 991 ms 247 ms 0.25x
stringBuilding 525 ms 107 ms 0.20x
recursion 508 ms 494 ms 0.97x
quicksortBench 410 ms wrong result Flutter: wrong result
Geometric mean 0.29x

Gate: within tolerance against scripts/flutter-bench/baseline; BEHIND FLUTTER on Compute (geomean of the VM workloads) (reported, not gated: a loss to Flutter on the web is currently accepted).

the JavaScript adapter needs a Chrome DevTools driver; sizes are reported and timings are not
This platform's adapter has not been exercised end to end before; treat the first published run as the thing under review.

linux

9 interleaved rounds; host load 0.26, 2.89, 2.38

Metric Codename One Flutter Ratio Winner
Installed size 111.1 MB 143.8 MB 1.29x Codename One
Executable code 13.9 MB 16.1 MB 1.16x Codename One
Download size (zipped) 80.8 MB 92.9 MB 1.15x Codename One
Cold start to first frame on screen 158 ms 242 ms 1.55x Codename One
Memory at rest 85.0 MB 226.0 MB 2.66x Codename One

Start-up and memory at rest are judged round by round: the ratio is the median of the per-round ratios, each from two launches made back to back, and the times and sizes shown are each side's median, so the ratio need not equal their quotient. Codename One was ahead in 9 of 9 rounds on cold start to first frame on screen; 9 of 9 rounds on memory at rest.

Compute -- the VM workloads (vm/benchmarks), run inside each app; time is the best of the app's own repetitions, higher ratio means Codename One is faster.

Workload Codename One Flutter Ratio
intArithmetic 74 ms 183 ms 2.47x
longArithmetic 56 ms 55 ms 0.98x
mathTranscendental 254 ms 277 ms 1.09x
arraySequential 16 ms 35 ms 2.19x
arrayRandom 258 ms 320 ms 1.24x
objectAllocation 28 ms 37 ms 1.32x
valueEscape 5 ms 7 ms 1.40x
hashMapChurn 50 ms 344 ms 6.88x
stringBuilding 33 ms 120 ms 3.64x
recursion 95 ms 257 ms 2.71x
quicksortBench 139 ms 149 ms 1.07x
Geometric mean 1.87x

Gate: OUTSIDE THE BASELINE against scripts/flutter-bench/baseline. Smaller than its baseline, which does not fail the gate: Download size (zipped) -0.01% -- rebaseline to tighten. To accept the move, download this platform's baseline-<platform>.json artifact and run python3 scripts/flutter-bench/flutter_baseline.py calibrate --pr 6052 --reason "<why these moved>" baseline-linux.json, then commit the overlay it writes.

This platform's adapter has not been exercised end to end before; treat the first published run as the thing under review.

macos

9 interleaved rounds; host load 2.85, 12.32, 11.81

Metric Codename One Flutter Ratio Winner
Installed size 123.6 MB 139.4 MB 1.13x Codename One
Executable code 32.5 MB 47.9 MB 1.48x Codename One
Download size (zipped) 85.4 MB 93.3 MB 1.09x Codename One
Cold start to first frame on screen 287 ms 378 ms 1.61x Codename One
Memory at rest 36.9 MB 52.3 MB 1.44x Codename One

Start-up and memory at rest are judged round by round: the ratio is the median of the per-round ratios, each from two launches made back to back, and the times and sizes shown are each side's median, so the ratio need not equal their quotient. Codename One was ahead in 8 of 9 rounds on cold start to first frame on screen; 9 of 9 rounds on memory at rest.

Compute -- the VM workloads (vm/benchmarks), run inside each app; time is the best of the app's own repetitions, higher ratio means Codename One is faster.

Workload Codename One Flutter Ratio
intArithmetic 101 ms 232 ms 2.30x
longArithmetic 64 ms 65 ms 1.02x
mathTranscendental 286 ms 299 ms 1.04x
arraySequential 11 ms 40 ms 3.64x
arrayRandom 272 ms 289 ms 1.06x
objectAllocation 25 ms 26 ms 1.04x
valueEscape 6 ms 12 ms 2.00x
hashMapChurn 35 ms 152 ms 4.34x
stringBuilding 21 ms 98 ms 4.67x
recursion 125 ms 249 ms 1.99x
quicksortBench 113 ms 125 ms 1.11x
Geometric mean 1.85x

Gate: within tolerance against scripts/flutter-bench/baseline. Smaller than its baseline, which does not fail the gate: Executable code -7.95%; Installed size -2.22%; Download size (zipped) -1.32% -- rebaseline to tighten. To accept the move, download this platform's baseline-<platform>.json artifact and run python3 scripts/flutter-bench/flutter_baseline.py calibrate --pr 6052 --reason "<why these moved>" baseline-macos.json, then commit the overlay it writes.

This platform's adapter has not been exercised end to end before; treat the first published run as the thing under review.

windows

9 interleaved rounds

Metric Codename One Flutter Ratio Winner
Installed size 107.5 MB 121.1 MB 1.13x Codename One
Executable code 11.2 MB 14.1 MB 1.26x Codename One
Download size (zipped) 77.7 MB 86.4 MB 1.11x Codename One
Cold start to first frame on screen 156 ms 253 ms 1.56x Codename One
Memory at rest 58.1 MB 92.5 MB 1.59x Codename One

Start-up and memory at rest are judged round by round: the ratio is the median of the per-round ratios, each from two launches made back to back, and the times and sizes shown are each side's median, so the ratio need not equal their quotient. Codename One was ahead in 9 of 9 rounds on cold start to first frame on screen; 9 of 9 rounds on memory at rest.

Compute -- the VM workloads (vm/benchmarks), run inside each app; time is the best of the app's own repetitions, higher ratio means Codename One is faster.

Workload Codename One Flutter Ratio
intArithmetic 81 ms 183 ms 2.26x
longArithmetic 63 ms 58 ms 0.92x
mathTranscendental 198 ms 282 ms 1.42x
arraySequential 12 ms 35 ms 2.92x
arrayRandom 262 ms 369 ms 1.41x
objectAllocation 25 ms 39 ms 1.56x
valueEscape 1 ms 7 ms 7.00x
hashMapChurn 48 ms 330 ms 6.88x
stringBuilding 35 ms 122 ms 3.49x
recursion 193 ms 264 ms 1.37x
quicksortBench 137 ms 146 ms 1.07x
Geometric mean 2.15x

Gate: within tolerance against scripts/flutter-bench/baseline. Smaller than its baseline, which does not fail the gate: Executable code -11.87%; Installed size -1.42%; Download size (zipped) -0.91% -- rebaseline to tighten. To accept the move, download this platform's baseline-<platform>.json artifact and run python3 scripts/flutter-bench/flutter_baseline.py calibrate --pr 6052 --reason "<why these moved>" baseline-windows.json, then commit the overlay it writes.

This platform's adapter has not been exercised end to end before; treat the first published run as the thing under review.

Codename One wins 26 of 26 measured metrics across 6 platform(s).

@shai-almog

shai-almog commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 236 screenshots: 236 matched.
✅ Native Apple Watch (watchOS, Core Graphics) screenshot tests passed.

@shai-almog

shai-almog commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 171 screenshots: 171 matched.
✅ Native Apple TV (tvOS, Metal) screenshot tests passed.

shai-almog and others added 2 commits October 22, 2026 13:56
… fallback open dialog picks several files

FileDialogHints held nothing but the key names for FileDialogRequest.hint(),
so the constants now live beside the method that takes them.

The Codename One open dialog, used by ports without a native one, answered a
multi-select request with a single file. It now shows a file tree whose files
toggle a check mark and returns every checked file in the order it was checked,
and the fallback reports FileDialogFeatures.MULTI_SELECT.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shai-almog
shai-almog merged commit 8dd3f16 into master Oct 22, 2026
62 of 88 checks passed
@shai-almog
shai-almog deleted the native-file-dialogs branch October 22, 2026 11:27
shai-almog added a commit that referenced this pull request Oct 23, 2026
Command.equals compares names, so the cancel and accept buttons must be
told apart by identity; master's #6052 tripped the forbidden-PMD gate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shai-almog added a commit that referenced this pull request Oct 23, 2026
PR CI's forbidden PMD list fails on master's FileDialogSupport (#6052): the
fallback dialog compares the picked Command by identity, which is right,
since Command.equals compares names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shai-almog added a commit that referenced this pull request Oct 24, 2026
…odename One apps (#5980)

* Desktop compatibility runtimes: Swing, SwingX, JavaFX and FXML over Codename One

swing-compat (java.awt, javax.swing, java.beans, javax.imageio and a SwingX
subset) is authored already relocated under com.codename1.desktopcompat;
javafx-compat is authored under the javafx names and relocated at build time.
desktop-compat-runtime holds what both layers share, including shims for the
host-backed JDK APIs a device lacks (java.io.File, java.net.URL,
java.nio.file, ResourceBundle, java.util.logging, java.util.prefs).
fxml-compiler turns FXML and JavaFX CSS into code and tables at build time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Build: one relocation pass for the Android, Swing and JavaFX layers

ClassRelocator applies every active layer in one pass; CompatRewrites
redirects the JDK members a device cannot have; the compliance check reports
unsupported desktop API under its original name. remap-compat and
import-desktop-project in Maven and Gradle, with the archetype wiring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Desktop compatibility: samples, integration tests, CI and documentation

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Read .properties bundles as UTF-8 first; never report AutoCloseable as Closeable

A stream bundle is UTF-8 when its bytes are well-formed UTF-8 and ISO-8859-1
otherwise, as the JDK has read them since Java 9. The compliance report no
longer reverses a shim whose target is itself a JDK class.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Fix CI: drop tests of the abandoned design, keep master's Android desugaring, doc snippet roles

The four core-unittests and AndroidDesugaringDependencyTest covered the
core JDK host and the nio desugaring this PR no longer has. The nio
desugar_jdk_libs variant clashed with the Flutter Android build
(DartList.reversed), so AndroidGradleBuilder is master's again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Flutter: DateTime.parse on the framework's regex engine; rebaseline the JS gallery sizes

dart.core.DateTime named java.util.regex, which no ParparVM target has and
nothing relocates in an ordinary application: every native Flutter build
failed on a missing java_util_regex_Pattern.h. It now uses
com.codename1.util.regex, as RegExp already did.

The PR's flutter-bench overlay justified the JavaAPI growth that moved to
#6044; its linux rows are dropped and the javascript rows recalibrated from
this PR's first gallery run on top of #6044 and #6055.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Flutter: DartList.reversed() clashes with Android's List.reversed()

Android API 35 gives java.util.List a reversed() answering a List, and
every Flutter plugin class extending DartList (dio's Interceptors) failed
to compile in the generated Android project. Dart's reversed getter is
now dartReversed() in Java; the transpiler emits that name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Extract the desktop runtime from its classes directory in a reactor build

A reactor build that stops before packaging (mvn test over several
modules, as the Java 8 CI leg runs) resolves the runtime to its
target/classes directory, and the remap found no runtime jar. The
directory is now read like the jar, leaving out com/codename1/impl the way
the module's jar does.

Also rebaselines the android and linux gallery sizes from their first run
on top of #6044 and #6055.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Mark the fallback open dialog's identity comparison for PMD

Command.equals compares names, so the cancel and accept buttons must be
told apart by identity; master's #6052 tripped the forbidden-PMD gate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ParparVM GC: never name a thread that may have exited

A collection that cannot stop a thread records a root miss and skips the
sweep, then names each missed thread with pthread_getname_np. The thread
it could not stop is usually one that is exiting: markDeadThread
deregisters it and the pthread ends, so the recorded handle can name a
thread that no longer exists, and glibc reads its freed descriptor. The
bulk conformance run, whose pool checks start and retire many threads,
crashed with SIGSEGV in this diagnostic right after the skip line
(vm-tests, StringBuilderGrowthApp, exit 139).

The name is now read only for a handle still registered in allThreads,
under the critical section markDeadThread takes, and blocked threads are
released before that lock is taken.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
shai-almog added a commit that referenced this pull request Oct 26, 2026
* Bastion sample: skeleton, double-entry multi-asset ledger and hash-chained audit log

Phase 1 of a security-showcase bank sample beside Savor and Wayline. The
ledger holds fiat and crypto alike, enforces zero-sum entries, non-negative
customer balances by conditional update, and idempotency keys; the audit log
is a SHA-256 chain appended in the transaction of the change it records.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: sign-in, second factor, passkeys, lockout and audited auth

Phase 2. An OAuth 2 authorization server (PKCE public client, five-minute
access tokens, rotating refresh tokens) and a JWT resource server for /api
with roles read from the account on every request. TOTP via http.mfa with
recovery codes, passkeys via http.webAuthn, rate limits on sign-in, codes,
registration and password changes, a temporary per-account lockout, explicit
security headers, and every sign-in, refusal, enrolment and password change
appended to the hash-chained audit log. Registration opens a USD checking
account; admin-only routes verify the audit chain and the books.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: accounts, transfers, payees, cards, signed step-up and device policy

BankingApi over the ledger: own-account transfers, payments to payees with a
cooling-off period, withdrawals, simulated deposits and card spends, per-
transfer and daily limits, idempotency keys with a retry-as-lookup on a
concurrent duplicate, ES256 request signing by a registered device key
(clock skew and nonce replay refused), and an attested/rooted device policy
behind a simulated integrity verifier. Every change is audited in its own
transaction. MoneyTest 12 cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: crypto exchange on the ledger, crypto withdrawals and limits, fresh sign-in for devices

Matching engine with price-time priority behind a market row lock, holds in
HOLD accounts, one balanced two-asset journal entry per trade, taker fee and
once-per-order rounding in the bank's favour, self-trade prevention, market
orders that never leave a hold. Allow-listed withdrawal addresses with
cooling-off, crypto limits valued at the index price, auth_time in access
tokens and a fresh sign-in (plus password without TOTP) to register a device.
Dev-profile market maker and price feed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: app foundation -- guarded network, PKCE sign-in with second factor and passkeys, device key and request signing, app lock, Security Center

Re-adds the common module. Every request passes one NetworkGuard (no
cleartext but the loopback dev server, a host allow-list, bundled pins,
AppShield delegated to). The device key is P-256 in portable Java (the
framework generates no EC keys and the iOS port signs RSA only), sealed in
a SecureEnvelope under a SecureStorage key, and signs the canonical form
now shared with the server (api/SignedRequest). Biometric lock on start,
resume and idle; secure screens, tapjacking blocking and clipboard
clearing; a Security Center that reports each protection honestly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Fix BigInteger division, modInverse and BigDecimal rounding; add EC P-256 key generation

TDivision.divide normalized with a 64-bit leading-zero count applied to a
32-bit digit (and the overflow test in step D3 used the same), so division,
mod and modInverse answered wrong values for ordinary 256-bit inputs. The
Montgomery/Hars inverses are replaced by extended Euclid. bitCount and
bitLength(int) had the same int-vs-long bug; BigDecimal.round always rounded
away from zero and floor threw for negatives.

KeyGenerator.ecP256() generates P-256 pairs through a new
generateEcKeyPair port method (JavaSE, Android, iOS). The iOS port now loads
EC keys in sign/verify (X9.62 DER signatures, as java.security returns) and
generates them with SecKey; a PKCS#8 EC key without its public point is
completed in Java (EcKeys) before signing, since SecKey cannot import one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: every screen -- onboarding, dashboard, accounts, transfers, payees, cards, exchange, crypto withdrawals, settings, admin

Onboarding registers with the server's password rule checked as typed, signs
in keeping the server session for a passkey ceremony, enrols TOTP with a QR
code (own byte-mode level-M encoder, checked against segno for versions 1-10
and every mask) and recovery codes, offers biometric unlock as a choice and
registers the device key. Money screens sign with RequestSigner, reuse one
idempotency key per payment across retries, and turn a missing-signature
refusal into an offer to register the device. Amounts are formatted and
parsed with integer math only (money/Amounts). Bundle_en.properties lists
every key; BundleTest keeps it complete.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: device key on core ES256, assets from the server, passkeys in Settings, pickers by id

DeviceKey/RequestSigner use KeyGenerator.ecP256 and Signature SHA256withECDSA
(DER to JOSE in RequestSigner); the hand-rolled P256 is gone. GET /api/assets
serves Ledger.assets and replaces the client's copied table. GET/DELETE
/api/account/passkeys plus a Settings section that adds a passkey through a
fresh kept sign-in. Pickers carry ids and make repeated labels distinct.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: CI workflow, live and web e2e, user's and implementor's guides

Fixes found on PostgreSQL, MySQL and the compiled server: cancel reads the
order behind the market lock, the server refuses MySQL above READ COMMITTED,
and the exchange avoids JDK APIs the compiled class library lacks. The app's
idle timer binds to the shown form.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: offer it as an Initializr template

Template.BASTION with its resources (synced from scripts/bastion), a preview
from the web e2e sign-in screen, the selector and summary entries, its README
section and brand colour, fixture and matrix checks, and check-template.sh run
by bastion.yml. Migrations (.sql) are now rewritten as text; --brand-tint and
--radius-small are set only where a template's theme declares them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: browser sign-in with PKCE and TOTP, passkeys in the JS port, amr claim for device registration

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: biometric-bound app key, PIN vault fallback, five languages, coded refusals

- security/Keys: one app key seals the device key and the refresh token
  (SealedStorage under SecureStorageTokenStore). Copies: SecureStorage's
  prompting tier (Keychain access control / Keystore user auth), a Vault
  opened by a 6-12 digit PIN (KdfProfile, peppered from the OS store,
  5 wrong tries wipe), and a plain copy only while neither exists.
- Lock/LockForm: biometric, then PIN, then sign in again; a stored session
  is read only after the unlock. Onboarding and Settings set both up.
- Security Center reports the app key, PIN, refresh token and lock honestly
  per platform.
- Android port: the biometric SecureStorage key is user-auth bound on every
  API level (was skipped on 33+) and invalidated by biometric enrolment; an
  old unbound key is replaced and its entries reported revoked.
- Server refusals carry stable codes (api/Refusal, backend Refused); the app
  maps them to error.<code> bundle keys. es/fr/de/he bundles, Lang.CODES
  restored, language choice in Settings; BundleTest checks completeness.
- Initializr template re-synced; guides updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: guide screenshots, diagrams and reference tables; website page

The user's guide shows every main screen, photographed from the browser build
by run-web-e2e.sh --guide (development profile, demo accounts, device policy
off so a payee payment can be shown). The implementor's guide gains figures
for the architecture, sign-in with PKCE and a second factor or passkey, a
signed payment, a trade's ledger entry and the audit chain, and tables of
security features (with whether each needs a cloud build), settings,
endpoints and the threat model. /bastion/ page and a flagship card.

The screenshots showed two theme faults, fixed: custom label styles without a
background painted an opaque white box (the dashboard's hero total was
invisible), and the three quick-action buttons truncated their labels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: client review round - sign-out wipes keys, owner-bound device keys, idempotency key signed, locale amounts, fail-closed guard

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion sample: server and framework review round

Idempotency keys scoped per owner under a c: prefix (system keys unreachable),
device registration needs otp/mfa/hwk in amr or the password, TOTP enrolment
needs a fresh sign-in, simulated integrity verifier only on dev profiles,
atomic lockout counting, order holds not movable by customers, fiat limits in
USD across currencies, profile-row lock for every cap, single-statement ledger
verify, paged audit verify, MariaDB tx_isolation fallback, uniform payee answers.

Framework: SecureStorage.setStrictBiometricBinding opt-in (Android default is
master's again; existing keys never deleted), EcKeys public point via a fixed
256-step Montgomery ladder with complete projective formulas.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sensitive clipboard API; Bastion reload keeps the session; password step-up for TOTP enrolment

- Core: ClipboardContent.setSensitive/setClearAfter. Display schedules the
  clear (only if nothing was copied since) through the new
  CodenameOneImplementation.clearClipboardContent. Android tags the clip
  with EXTRA_IS_SENSITIVE (API 24+ extras, honoured on 33+) and clears only
  its own clip; iOS republishes the pasteboard local only with an expiry
  date (IOSNative.restrictClipboard). SensitiveClipboardTest.
- Bastion: a reload (or restart) landed on the sign-in form because the
  start looked for the session under SealedStorage's account name while
  SecureStorageTokenStore writes under its own prefix. Session now marks
  saved sessions itself under its own key (Session.Marked);
  StoredSessionTest. run-web-e2e reload step passes.
- Bastion: adding an authenticator app after a password-only sign-in
  needs the password on start and confirm (TotpStartDto, TotpCodeDto
  password); client prompts. "Copy codes" restored via sensitive clips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion review round 2: step-up lockout, signed card/payee/device changes, USD-valued limits, clipboard ownership

- AndroidImplementation.java: restore master's CRLF line endings; only the clipboard hunks differ.
- SignInGuard.recheck: in-session password checks (TOTP enrolment, device registration, device
  revoke) refuse a locked account first, count a wrong password, clear on success, and do not
  count a missing one.
- Unfreezing a card and raising its limit need a signature from a trusted device; renaming and
  removing a payee are signed; revoking a device (now POST /api/devices/{id}/revoke) needs a
  device signature or the password. Client signs all of them; docs and API table updated.
- Payee cooling-off and the step-up threshold value fiat in USD per currency.
- Card spends re-read the card behind its row lock inside the money transaction.
- Default clearClipboardContent clears only while the clipboard still holds the copied text;
  iOS resets its expiry flag on every copy; Protect's timer only forgets the digest.
- EcKeys uses modInverse (fixed on this branch); stale session marker dropped when the store is
  empty; taker-seller fee test on one-cent fills.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion review round 3: signed and limited orders with a price collar, fresh step-up, signed card/address/passkey changes, PIN counter in the secure store, translated Security Center

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion review round 4: locking frozen-account read, transition-free lock, re-armed idle timer, Hebrew passkey term

- LedgerAccountRepository.frozenNow is a no-op UPDATE, so it reads the
  latest committed row and locks it on SQLite, PostgreSQL and MySQL alike.
- Lock disposes an open dialog without its closing animation and the lock
  screen shows with no transition, so the form beneath is never painted.
- Lock.tick re-arms its timer in finally.
- Comments: placeOnce is woven despite being private and self-called; the
  collar never follows fills; counting both trade sides is deliberate.
- Docs: PIN counter lives in the OS secure store; the clipboard clears
  after a minute or at the next start.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* CI: guide snippets by include, copyright headers, Play Integrity raises minSdk to 21

Bastion's guides moved their shell blocks into docs/demos snippets; the new
core tests got the standard header and the Harmony/Bouncy Castle big-number
sources are listed as third-party; android.playIntegrity now lifts minSdk to
21, which com.google.android.play:integrity declares and the manifest merger
enforced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* iOS: publish a sensitive clip local only and expiring on the first write

restrictClipboard used to re-publish the pasteboard with LocalOnly and the
expiry after setClipboardContent had already written it normally, leaving a
window in which Universal Clipboard could sync the value. It now arms the
options and setClipboardContent's single setItems:options: carries them.
Native names are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion: a passkey spares the password only when the user was verified

Devices.register and SecondFactor treated amr "hwk" alone as strong, so a
passkey assertion without user verification skipped the password. Both now
need mfa/otp, or hwk together with user; MoneyTest covers hwk alone. The
implementors guide's shell blocks move to the docs/demos snippet file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion app: step-up dialog field keeps its height; client matches the server rule

Dialog.show stretched the lone password field to ~105px, which the web e2e
does not recognise as a field (CI timed out on 'Confirm it is you'); it is
now enclosed in a BoxLayout. DeviceSetup and onboarding ask for the password
under the same rule the server applies (mfa/otp, or hwk with user) instead
of whether an app is on the account now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Initializr: resync the Bastion template with the sample

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion guide: US spelling for LanguageTool

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion web e2e: check what a field holds, and retype on a doubled keystroke

CI typed a six-digit code that arrived as seven digits and was refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion: the bank's books - chart of accounts, statements, close, audit

Chart of accounts over the ledger (positive = credit), journal, general
ledger, T-accounts, trial balance, balance sheet and income statement in
USD; period close with immutable closed periods; reversals; reconciliation
breaks; an AUDITOR role whose reads are on the audit chain; per-entity
audit trails, a chain report naming the first broken link and CSV/JSON
evidence exports; maker-checker approval above a threshold; chart and
candle endpoints; weeks of demo history.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* FileDialogSupport: mark the intentional Command identity check for PMD

PR CI's forbidden PMD list fails on master's FileDialogSupport (#6052): the
fallback dialog compares the picked Command by identity, which is right,
since Command.equals compares names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion app: charts, a staff console, and one way back on every screen

Every screen now has a back arrow or the side menu, never both. Sign-in and
lock use a branded landing band that respects the safe area, and the app
icon is a vector shield. Charts (com.codename1.charts) are on the dashboard,
the account, the exchange and the drill-downs (transaction, statement). The
staff console replaces AdminForm: journal, general ledger and T-accounts,
statements, reconciliation, period close, maker-checker approvals, audit
chain, trail, access log and evidence export. It has a sidebar on a desktop
and a section picker on a phone, and the auditor gets it read-only. New
strings are in all five bundles. Guide screenshots, the Initializr preview
and the template are regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion: refined charts, honest volume, fitted phone tables, composed preview

The console's volume and entry counts leave out order holds and releases:
they move a customer's own money into escrow and back, and the market
maker's requotes buried every earlier day under today. The market maker no
longer posts a second million-dollar float when the demo history funded it.
The last two days of history trade densely, so hourly candles have real
ranges. Money axes read $8k, the greeting uses the first name, the console
loses its duplicate heading, phone tiles and the statement fit the width,
and the Initializr preview is composed from the phone and the console.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion: close the red-team findings in the books

- Maker-checker fails closed: an unpriced request waits, and what the maker
  posted without a checker in the last 24h counts towards the threshold.
  Pricing is asked, not caught, since a caught refusal dooms the transaction.
- A self-approval's APPROVAL_REFUSED row now commits.
- The journal evidence export pages through every entry.
- General ledger and T-account total in SQL and flag truncated listings.
- CSV guard covers leading tab and CR; periods() is a recorded staff read.
- Console: entries a day counts distinct entries; toasts follow the status;
  the phone statement fits its opening and closing rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion guide: name the chart styles rather than a wildcard

check-guide-api-names read `BnChart*` as a misspelled class name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion guides: three LanguageTool findings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion: serialize a maker's approvals, explain a refused e2e code

Approvals.adjust/reverse hold the maker's profile row (a no-op UPDATE,
as ProfileRepository.hold) before the idempotency lookup and the 24h
un-checked SUM, so concurrent just-under-threshold requests cannot all
post without a checker; a maker with no profile fails closed and waits.
BooksTest races eight such requests.

web-e2e.mjs: the authenticator key is re-read until it is 32 valid
base32 characters, and a refused code logs the test step, a secret
length/hash fingerprint, the server's Date skew and the last requests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Android clipboard: clear a timed clip by in-process ownership, not read-back

The description reads null for a background app on Android 10+, so the
timed clear almost never fired. Ownership is now a per-copy token, dropped
by the clip-changed listener and re-checked on resume. Bastion: sign-safe
opening balance, and a test seam that holds the per-maker race window open
so the lock's absence fails on PostgreSQL. BigDecimal.round documents HALF_UP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Android clipboard: defer a background clear until the clip is provably ours

A timed clear that fires while the description is unreadable (background,
API 29+) no longer clears blind; it waits for resume and runs only if the
token still matches. Resume resets the clip-change count a background
clear could leave unconsumed. Bastion's approvals test seam is now
package-private, reached through a test-only hook.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Android clipboard: retry a deferred clear on window focus, document process death

Android 10+ reads the clipboard only with window focus, which arrives after
onResume; retry the pending clear from onWindowFocusChanged(true). Document
that the deferred clear does not survive process death and how Bastion covers
it. Restore getNativeThemeSettings' original line endings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion: keep the clipboard record until a read decides it, key its digest

The leftover check now runs after a form shows, on resume and after the
clear falls due, keeps the record while the read answers null, and skips
iOS. The digest is HMAC-SHA256 under a key in secure storage. Android:
give the focus and resume clip checks their own doc comments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion web e2e: let a typed field settle before reading it back

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Flutter bench: accept the Android code-size move from the clipboard handling

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Initializr: generate Bastion's probes at its own release, test the refusal below it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion: button spacing, a real card, full receipts and statements, no cut-off values

- Buttons: smaller consistent label (2.5mm) with side padding; Ui.across puts
  the theme's gap (bnButtonGapMm) between buttons and wraps a row that does
  not fit (main action on its own row) instead of shrinking or cutting labels.
- Cards: CardFace draws an ID-1 card (1.586:1, rounded, gradient, chip, brand,
  number in fours, holder, expiry, frozen overlay); details (status, type,
  account, expiry, daily limit with a used-today meter) and recent card payments.
- Landing headings wrap; the authenticator key shows whole as monospaced
  groups of four.
- Receipt: "Receipt" title with a close button; status, from, to, amount, fee,
  balance after, time, note and the full Reference wrapping.
- Statement: header with account, period, opening/closing and totals; columns
  for description, category, reference, in/out, amount and running balance,
  a column chooser, more columns on wide windows, and every row opens in full.
- PostingDto carries the entry's kind and memo for descriptions and categories.
- l10n for en/es/de/fr/he; web e2e reads the grouped key and skips read-only
  text areas; screenshots regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion: copy buttons, printable reports, and sign-in held to the strongest factor

- Ui.copyable / Ui.copyButton: selectable value plus a copy icon; secrets
  (keys, account and card IDs, recovery codes) go through Protect.copy and
  clear themselves. Used for references, ledger entries and postings,
  account/card IDs, coin addresses, passkey and device key IDs, entry IDs,
  audit head hash and evidence SHA-256.
- Printout: a report laid out as monospaced lines (header, tables, totals),
  drawn on an image and printed through com.codename1.printing.Printer.
  Print on the statement, receipt, transaction, journal entry, general
  ledger, trial balance, balance sheet, income statement, audit chain,
  audit trail, access log and evidence export; no button where printing is
  unsupported. Table records its rows for printing.
- Sign-in offers passkey, then biometric unlock of the stored session, then
  password and code. The server requires user verification on passkeys,
  and SignInGuard refuses a password (and an authenticator code) for an
  account with a passkey; password plus a recovery code is the recovery
  path. AuthTest covers both; web-e2e checks the refusal end to end.
- Developer guide, five bundles and guide screenshots updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* JavaScript port: typing on a form with text selection on is no longer lost

A press queued 'finish editing' through a thread-spawning callSerially that
ran after the same click had opened the field, closing it again; and the
legacy editor committed on blur in a queued callback, after a button's action
had read the model. The press now finishes only the session it saw, and blur
commits the value at once. Regression check: review=selectionsignin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion: print reports as a paginated PDF with repeated headers and page numbers

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion: errors and sentences wrap, text selection on every form

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion web e2e: one tap opens a market, no retry

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Initializr: resync the Bastion template with the sample

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: Bastion guides, contractions for Vale

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Security: Keccak-256, SHA3-256 and secp256k1 ECDSA in core, shared with the backend

The two primitives an Ethereum wallet needs, in portable Java so the
Bastion sample can sign chain transactions on the device or on the server
with the same class.

Hash gains KECCAK256 (original 0x01 padding, what Ethereum hashes with)
and SHA3_256 (FIPS 202, 0x06), one Keccak-f[1600] sponge in
MessageDigestImpl behind both; Hmac learns the 136-byte rate as their
block size.

Secp256k1 is written from the math, not ported from libsecp256k1: a 16x16
bit limb field whose reduction is a few bounded fold-and-carry passes, the
Renes-Costello-Batina complete projective addition (no doubling or
infinity special case to branch on), and a 4-bit fixed-window ladder with a
constant-time table scan. Everything that touches a private key or nonce
is constant time; verify and recover reuse the same code. Signatures are
RFC 6979 deterministic, low-S, and carry the recovery id; verify rejects
high-S as libsecp256k1 does, recover accepts it as ecrecover does.
Private and public tweak addition and point addition cover BIP32.

Tests: Keccak and SHA3 known answers including the NIST million-a
multi-block vector, generator multiples, the published RFC 6979 secp256k1
vectors, the Ethereum address of a published test key, recover(sign(h)),
tampering, high-S handling and tweak agreement.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Bastion: real Ether on chain, security audit fixes, checklist, UI polish

- chain/: EIP-1559 signing, RLP, EIP-55, BIP-32/44 keys, JSON-RPC node
  client; per-customer deposit addresses, confirmation-depth scanning that
  stops on a reorg, sweeps, withdrawals under a lease and compare-and-set
  states, fees posted at the receipt's cost, and a reserves breaker that
  holds a withdrawal custody cannot back. Known-answer tests against
  eth-account, and run-chain-test.sh drives a geth development node (CI job).
- Audit fixes: payee removal keeps its cooling-off, a device needs a second
  factor, staff need one for the console, daily caps on new payees and
  addresses, rate limits per principal, production refuses default secrets,
  expired nonces purged, ETH addresses checked by EIP-55.
- Console custody panel, Receive crypto screen with an EIP-681 QR code.
- UI: chips instead of stretched badges, gaps between console buttons and
  charts, a spinner with skeleton cards while loading; the web e2e waits
  for content before each screenshot.
- Initializr e2e: a template is offered only from its release floor, and
  the pinned versions must be releases, never snapshots.
- Implementor's guide: on a real chain, and a security checklist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: compilable secp256k1 snippet, Bastion guide prose gates

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bastion: adopt master's Instant mapping and PKI; App Attest; skill update

- Entities hold java.time.Instant timestamps (same BIGINT columns, no
  migration); repository time parameters are Instant, DTOs stay epoch ms.
- AppAttestVerifier: an iPhone's App Attest attestation is verified on the
  server with the backend PKI -- chain to Apple's root, the nonce bound to
  the device key being registered, app id, counter and environment --
  when bastion.appattest.app-id is set.
- Skill: Bastion in the demo apps reference; backend reference covers
  exception handlers, advice, validation, interceptors, java.time in the
  ORM, streaming bodies and HttpProxy, PKI, ECDH, Keccak and secp256k1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant